package console

import (
	"fmt"
	"log"
	"runtime"
	"time"
)

// 定义6个常量，每个常量代表一个布尔值为true的位置
const (
	LEVEL_DEBUG = 1 << iota
	LEVEL_INFO
	LEVEL_WARN
	LEVEL_ERROR
	LEVEL_FATAL
	PRINT_SRC_FILE
)

type consoleFunc func(format string, a ...any)

var printSrcFileEmptyFunc = func() {}

type Console struct {
	Debug consoleFunc
	Info  consoleFunc
	Warn  consoleFunc
	Error consoleFunc
	Fatal consoleFunc
}

func NewConsole(params int) *Console {
	levelDebug := params&LEVEL_DEBUG != 0
	levelInfo := params&LEVEL_INFO != 0
	levelWarn := params&LEVEL_WARN != 0
	levelError := params&LEVEL_ERROR != 0
	levelFatal := params&LEVEL_FATAL != 0
	srcFile := params&PRINT_SRC_FILE != 0
	result := &Console{
		Debug: func(format string, a ...any) {},
		Info:  func(format string, a ...any) {},
		Warn:  func(format string, a ...any) {},
		Error: func(format string, a ...any) {},
		Fatal: func(format string, a ...any) {},
	}
	if levelDebug {
		result.Debug = result.debugFunc
	}
	if levelInfo {
		result.Info = result.infoFunc
	}
	if levelWarn {
		result.Warn = result.warnFunc
	}
	if levelError {
		result.Error = result.errorFunc
	}
	if levelFatal {
		result.Fatal = result.fatalFunc
	}
	if srcFile {
		printSrcFileEmptyFunc = printSrcFileFunc
	}
	return result
}

// Log 打印日志的函数
func output(level int, msg string) {
	// 格式化日志等级字符串，添加颜色
	levelStr := generateLevel(level)
	now := generateNowTime()
	printSrcFileEmptyFunc()
	fmt.Printf("%s |%s| %s\n", now, levelStr, msg)
}

// debugFunc 打印DEBUG等级的日志
func (c *Console) debugFunc(format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	output(LEVEL_DEBUG, msg)
}

// infoFunc 打印INFO等级的日志
func (c *Console) infoFunc(format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	output(LEVEL_INFO, msg)
}

// warningFunc 打印WARNING等级的日志
func (c *Console) warnFunc(format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	output(LEVEL_WARN, msg)
}

// errorFunc 打印ERROR等级的日志
func (c *Console) errorFunc(format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	output(LEVEL_ERROR, msg)
}

// fatalFunc 打印FATAL等级的日志
func (c *Console) fatalFunc(format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	output(LEVEL_FATAL, msg)
}

func printSrcFileFunc() {
	_, file, line, ok := runtime.Caller(3) // 注意这里要改为3，因为调用堆栈深入了一层
	if !ok {
		log.Println("无法获取调用者信息")
		return
	}
	fileStr := fmt.Sprintf("\033[1;95m%s:%d\033[0m", file, line)
	// 打印格式化的日志
	fmt.Printf("%s\n", fileStr)
}

func generateNowTime() string {
	return time.Now().Format("2006-01-02 - 15:04:05.000")
	// return fmt.Sprintf("\033[44;97m%s\033[0m", time.Now().Format("2006-01-02 - 15:04:05.000"))
}

func generateLevel(level int) string {
	// logColor 用于根据日志等级设置背景色和文字色
	logColor := map[int]string{
		LEVEL_DEBUG: fmt.Sprintf("\033[44;97m%-5s\033[0m", "DEBUG"),  //
		LEVEL_INFO:  fmt.Sprintf("\033[102;97m%-5s\033[0m", "INFO"),  //
		LEVEL_WARN:  fmt.Sprintf("\033[103;97m%-5s\033[0m", "WARN"),  //
		LEVEL_ERROR: fmt.Sprintf("\033[101;97m%-5s\033[0m", "ERROR"), //
		LEVEL_FATAL: fmt.Sprintf("\033[41;97m%-5s\033[0m", "FATAL"),  //
	}
	return fmt.Sprintf(logColor[level])
}

func PrintLevelBind() {
	fmt.Printf("整数 | %s | %s | %s | %s | %s | %s\n",
		generateLevel(LEVEL_DEBUG),
		generateLevel(LEVEL_INFO),
		generateLevel(LEVEL_WARN),
		generateLevel(LEVEL_ERROR),
		generateLevel(LEVEL_FATAL),
		"SrcFile",
	)
	// 遍历所有可能的整数值（0到2^6-1）
	for i := 0; i < 64; i++ {
		func() {
			// 解析整数为六个布尔值
			levelDebug := fmt.Sprintf("%t", i&LEVEL_DEBUG != 0)
			levelInfo := fmt.Sprintf("%t", i&LEVEL_INFO != 0)
			levelWarn := fmt.Sprintf("%t", i&LEVEL_WARN != 0)
			levelError := fmt.Sprintf("%t", i&LEVEL_ERROR != 0)
			levelFatal := fmt.Sprintf("%t", i&LEVEL_FATAL != 0)
			srcFile := fmt.Sprintf("%t", i&PRINT_SRC_FILE != 0)

			fmt.Printf("%3d | %s | %s | %s | %s | %s | %s\n", i,
				fmt.Sprintf("\033[44;97m%-5s\033[0m", levelDebug),  //
				fmt.Sprintf("\033[102;97m%-5s\033[0m", levelInfo),  //
				fmt.Sprintf("\033[103;97m%-5s\033[0m", levelWarn),  //
				fmt.Sprintf("\033[101;97m%-5s\033[0m", levelError), //
				fmt.Sprintf("\033[41;97m%-5s\033[0m", levelFatal),  //
				srcFile,
			)
		}()
	}
}
